package cn.zwk.domain.system.service.impl;

import cn.zwk.common.exception.BusinessException;
import cn.zwk.common.utils.tree.TreeDrive;
import cn.zwk.domain.system.converter.MenuConverter;
import cn.zwk.domain.system.constants.MenuConstant;
import cn.zwk.domain.system.model.ViewComponent;
import cn.zwk.domain.system.model.dto.MenuDTO;
import cn.zwk.domain.system.model.vo.MenuComponentVo;
import cn.zwk.domain.system.model.vo.MenuLabelVo;
import cn.zwk.domain.system.service.IMenuService;
import cn.zwk.domain.system.support.MenuProperties;
import cn.zwk.repository.MenuRepository;
import cn.zwk.repository.po.Menu;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

@Service
public class MenuServiceImpl implements IMenuService {
    @Autowired
    private MenuRepository menuRepository;
    @Autowired
    private MenuProperties menuProperties;
    @Autowired
    private MenuConverter menuConverter;

    @Override
    public List<Menu> treeRoutes() {
        List<Menu> list = menuRepository.lambdaQuery()
                .ne(Menu::getType, MenuConstant.MenuType.PERMISSION)
                .list();
        TreeDrive<Menu> treeDrive = new TreeDrive<>(list);
        return treeDrive.getTreeList();
    }

    @Override
    public List<Menu> treeMenus() {
        TreeDrive<Menu> treeDrive = new TreeDrive<>(this.menuRepository.list());
        return treeDrive.getTreeList();
    }


    @Override
    @Transactional
    public boolean addMenu(MenuDTO menuDto) {
        Menu po = menuConverter.toPo(menuDto);
        ViewComponent component = menuProperties.getComponent(menuDto.getComponentId());
        po.setComponent(component.getComponent());
        menuRepository.save(po);
        List<Menu> collect = component.getPermissions().stream().map(o -> {
            Menu menu = new Menu();
            menu.setName(o);
            menu.setParentId(po.getId());
            menu.setType(MenuConstant.MenuType.PERMISSION);
            menu.setPerm(po.getPerm()+":"+o);
            return menu;
        }).collect(Collectors.toList());
        return menuRepository.saveBatch(collect);
    }

    @Override
    public boolean editMenu(MenuDTO menuDto) {
        List<Menu> list = menuRepository.list();
        TreeDrive<Menu> treeDrive = new TreeDrive<>(list);
        if (treeDrive.hasLoop(menuDto.getId(), menuDto.getParentId())) {
            throw new BusinessException("不能下移到自己或孩子");
        }
        return menuRepository.updateById(menuConverter.toPo(menuDto));
    }

    @Override
    public boolean deleteMenu(Long id) {
        List<Menu> list = menuRepository.list();
        TreeDrive<Menu> treeDrive = new TreeDrive<>(list);
        List<Menu> treeNodes = treeDrive.getTreeNodes(id);
        List<Long> ids = treeNodes.stream().map(Menu::getId).collect(Collectors.toList());
        return menuRepository.removeBatchByIds(ids);
    }


    @Override
    public List<MenuComponentVo> menuComponentList() {
        List<ViewComponent> components = menuProperties.getComponents();
        return menuConverter.toMenuComponentVo(components);
    }

    @Override
    public List<MenuLabelVo> listMenuOptions() {
        List<Menu> list = menuRepository.list();
        TreeDrive<Menu> treeDrive = new TreeDrive<>(list);
        return buildMenuLabelVo(treeDrive.getTreeList());
    }

    @Override
    public MenuDTO getInfo(Long id) {
        Menu byId = menuRepository.getById(id);
        MenuDTO menuDto = new MenuDTO();
        BeanUtils.copyProperties(byId,menuDto);
        return menuDto;
    }

    public List<MenuLabelVo> buildMenuLabelVo(List<Menu> list) {
        return list.stream().map(o -> {
            MenuLabelVo menuLabelVo = new MenuLabelVo();
            menuLabelVo.setId(o.getId());
            menuLabelVo.setName(o.getName());
            menuLabelVo.setChildren(buildMenuLabelVo(o.getChildren()));
            return menuLabelVo;
        }).collect(Collectors.toList());
    }
}
